package com.demo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/** 
 * 泛型工具类 
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class GenericsUtils {

	/** 
	 * 通过反射,获得指定类的父接口的泛型参数的实际类型.
	 */
	public static <T> Class<T> getSuperInterfaceGenricType(Class clazz, Class interfaceClass) {
		return getSuperInterfaceGenricType(clazz, interfaceClass, 0);
	}

	/** 
	 * 通过反射,获得指定类的父接口的泛型参数的实际类型.
	 */
	public static <T> Class<T> getSuperInterfaceGenricType(Class clazz, Class interfaceClass, int index) {
		if (!interfaceClass.isInterface()) { //
			throw new RuntimeException("Type " + interfaceClass + " 不是接口类型.");
		}
		Type[] interfaces = clazz.getGenericInterfaces();

		for (Type type : interfaces) {
			if (type instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType) type;
				if (parameterizedType.getRawType().equals(interfaceClass)) {//
					return getActualTypeArgument(type, index);
				}
			}
		}
		throw new RuntimeException("Class " + clazz + " 没有实现接口.");
	}

	/** 
	 * 通过反射,获得指定类的父接口的泛型参数的实际类型.
	 */
	public static <T> Class<T> getSuperInterfaceGenricType(Class clazz) {
		return getSuperInterfaceGenricType(clazz, 0);
	}

	/** 
	 * 通过反射,获得指定类的父接口的泛型参数的实际类型.
	 */
	public static <T> Class<T> getSuperInterfaceGenricType(Class clazz, int index) {
		return getActualTypeArgument(clazz.getGenericInterfaces()[0], index);
	}

	/** 
	 * 通过反射,获得指定类的父类的泛型参数的实际类型. 如DaoSupport
	 */
	public static <T> Class<T> getSuperClassGenricType(Class clazz, int index) {
		return getActualTypeArgument(clazz.getGenericSuperclass(), index);
	}

	/** 
	 * 通过反射,获得指定类的父类的第一个泛型参数的实际类型. 如DaoSupport 
	 */
	public static <T> Class<T> getSuperClassGenricType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/** 
	 * 通过反射,获得方法返回值泛型参数的实际类型. 如: Map<String, User> getNames();
	 */
	public static <T> Class<T> getMethodGenericReturnType(Method method, int index) {
		return getActualTypeArgument(method.getGenericReturnType(), index);
	}

	/** 
	 * 通过反射,获得方法返回值第一个泛型参数的实际类型. 如: Map<String, User> getNames();
	 */
	public static <T> Class<T> getMethodGenericReturnType(Method method) {
		return getMethodGenericReturnType(method, 0);
	}

	/** 
	 * 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型. 如: Map<String, User> getNames();
	 */
	public static List<Class> getMethodGenericParameterTypes(Method method, int index) {
		Type type = getType(method.getGenericParameterTypes(), index);

		List<Class> results = new ArrayList<Class>();
		if (type instanceof ParameterizedType) {
			results.addAll(Arrays.asList(getActualTypeArguments((ParameterizedType) type)));
		}
		return results;
	}

	/** 
	 * 通过反射,获得方法输入参数第一个输入参数的所有泛型参数的实际类型. 如: Map<String, User> getNames();
	 */
	public static List<Class> getMethodGenericParameterTypes(Method method) {
		return getMethodGenericParameterTypes(method, 0);
	}

	/** 
	 * 通过反射,获得Field泛型参数的实际类型. 如: Map<String, User> names; 
	 */
	public static <T> Class<T> getFieldGenericType(Field field, int index) {
		return getActualTypeArgument(field.getGenericType(), index);
	}

	/** 
	 * 通过反射,获得Field泛型参数的实际类型. 如: Map<String, User> names; 
	 */
	public static <T> Class<T> getFieldGenericType(Field field) {
		return getFieldGenericType(field, 0);
	}

	// ----------------------------------------------------------
	// function
	// ----------------------------------------------------------

	/**
	 * 获取实际类型
	 */
	private static final Type getType(Type[] types, int index) {
		if (index >= types.length || index < 0) { //
			throw new ArrayIndexOutOfBoundsException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
		}
		return types[index];
	}

	/**
	 * 获取实际类型
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，所以直接返回 
	 *         <code>Object.class</code> 
	 */
	private static final <T> Class<T> getActualTypeArgument(Type type, int index) {
		if (type instanceof ParameterizedType) {//
			return getActualTypeArgument((ParameterizedType) type, index);
		}
		return (Class<T>) Object.class;

	}

	/**
	 * 获取实际类型
	 */
	private static final <T> Class<T> getActualTypeArgument(ParameterizedType type, int index) {
		Type[] fieldArgTypes = type.getActualTypeArguments();
		if (index >= fieldArgTypes.length || index < 0) { //
			throw new ArrayIndexOutOfBoundsException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
		}
		return (Class) fieldArgTypes[index];
	}

	/**
	 * 获取实际类型
	 */
	private static final <T> Class[] getActualTypeArguments(ParameterizedType type) {
		Type[] types = type.getActualTypeArguments();
		Class[] classes = new Class[types.length];
		for (int i = 0; i < classes.length; i++) {
			classes[i] = (Class) types[i];
		}
		return classes;
	}
}